#include "error.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

using std::string;

namespace {

const char kDumpCore[] = "DUMP_CORE";

enum ExitMethod {
  NORMAL,
  IMMEDIATE,
};

void terminate(ExitMethod method) {
  if (getenv(kDumpCore)) {
    abort();
  } else if (method == NORMAL) {
    exit(EXIT_FAILURE);
  } else {
    _exit(EXIT_FAILURE);
  }
}

const int kBufSize = 500;

void print_error(bool use_errnum, int errnum,
                 bool flush_stdout,
                 const string& format, va_list ap) {
  char user_message[kBufSize];
  vsnprintf(user_message, kBufSize, format.c_str(), ap);

  char error_message[kBufSize];
  if (use_errnum) {
    snprintf(error_message, kBufSize, " [%d %s]:", errnum, strerror(errnum));
  } else {
    snprintf(error_message, kBufSize, ":");
  }

  char message[kBufSize];
  snprintf(message, kBufSize, "ERROR%s %s\n", error_message, user_message);

  if (flush_stdout) {
    fflush(stdout);
  }
  fputs(message, stderr);
  fflush(stderr);
}

}

void error(const string& format, ...) {
  va_list ap;
  va_start(ap, format);
  print_error(true, errno, true, format, ap);
  va_end(ap);

  terminate(NORMAL);
}

void fatal(const string& format, ...) {
  va_list ap;
  va_start(ap, format);
  print_error(false, 0, true, format, ap);
  va_end(ap);

  terminate(NORMAL);
}

void usage(const string& format, ...) {
  fflush(stdout);

  fprintf(stderr, "Usage: ");
  va_list ap;
  va_start(ap, format);
  vfprintf(stderr, format.c_str(), ap);
  va_end(ap);
  fflush(stderr);

  exit(EXIT_FAILURE);
}
